package com.totoro.tymapping.task;

import com.totoro.tymapping.TyMapping;
import com.totoro.tymapping.bo.CheckParseBo;
import com.totoro.tymapping.constants.ConditionConst;
import com.totoro.tymapping.data.ComputeResult;
import com.totoro.tymapping.enums.ComputeExecutorEnum;
import com.totoro.tymapping.enums.ConditionExecutorEnum;
import com.totoro.tymapping.enums.SlotParseExecutorEnum;
import com.totoro.tymapping.executor.compute.ComputeExecutor;
import com.totoro.tymapping.executor.condition.ConditionExecutor;
import com.totoro.tymapping.executor.slotparse.SlotParseExecutor;
import com.totoro.tymapping.pojo.Config;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author Totoro
 * @version 0.1.0
 * @date 2025/8/13 - 15:11
 * @description 检测解析任务
 **/
public class CheckParseTask extends BukkitRunnable {

    private final TyMapping plugin;

    public CheckParseTask(TyMapping plugin) {
        this.plugin = plugin;
    }
    @Override
    public void run() {
        Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
            Map<UUID, CheckParseBo> map = plugin.getCheckTaskManager().getPlayerCheckParseBoMap();
            Config config = plugin.getConfigManager().getConfig();
            map.forEach((uuid, other) -> {
                // 判断玩家是否存在和在线
                Player player = Bukkit.getPlayer(uuid);
                if(null == player || !player.isOnline()) {
                    plugin.getCheckTaskManager().remove(uuid);
                    return;
                }
                // 获取所有检测组，优先检测到哪个就用哪个检测组
                CheckParseBo checkParseBo = new CheckParseBo();
                for (Map.Entry<String, Config.Check> entry : config.getChecks().entrySet()) {
                    String checkId = entry.getKey();
                    Config.Check check = entry.getValue();
                    // 先解析条件是否满足
                    List<String> condition = check.getCondition();
                    // 先解析针对角色的条件，也就是per notper papi
                    List<String> roleCondition = condition.stream().filter(cd -> !cd.startsWith(ConditionConst.NAME) &&
                            !cd.startsWith(ConditionConst.LORE)).collect(Collectors.toList());
                    // 角色解析结果
                    boolean roleParseResult = true;
                    for (String rCd : roleCondition) {
                        ConditionExecutor conditionExecutor = ConditionExecutorEnum.getConditionExecutor(rCd);
                        if(null == conditionExecutor) {
                            roleParseResult = false;
                            break;
                        }
                        Boolean execute = conditionExecutor.execute(rCd, player, null);
                        if(! execute) {
                            roleParseResult = false;
                            break;
                        }
                    }


                    // 解析槽位结果
                    List<String> slot = config.getReadSlot();
                    boolean slotParseResult = false;
                    for (String lineSlot : slot) {
                        SlotParseExecutor slotParseExecutor = SlotParseExecutorEnum.getSlotParseExecutor(lineSlot);
                        if(null == slotParseExecutor) {
                            continue;
                        }
                        Boolean execute = slotParseExecutor.execute(lineSlot, condition, player);
                        if(execute) {
                            slotParseResult = true;
                            break;
                        }
                    }


                    // 如果两个结果都为true则应用这套检测组然后结束循环，否则继续匹配
                    if(roleParseResult && slotParseResult) {
                        // 可以应用这套检测组，那么解析属性
                        List<String> finalAttribute = check.getAttribute().stream().map(attribute -> {
                            // 执行计算解析器，如果不为空则解析替换表达式
                            ComputeExecutor computeExecutor = ComputeExecutorEnum.getComputeExecutor(attribute);
                            if (computeExecutor != null) {
                                ComputeResult computeResult = computeExecutor.execute(plugin, attribute, player);
                                attribute = attribute.replace(computeResult.getOriginalTag(),
                                        plugin.getConfigManager().getConfig().getAttributeValueRound()
                                                ? String.valueOf(computeResult.getResult().intValue()) : String.valueOf(computeResult.getResult().doubleValue()));
                            }
                            return attribute;
                        }).collect(Collectors.toList());
                        // 创建checkParseBo
                        checkParseBo = new CheckParseBo(checkId, finalAttribute, check.getEffect());
                        break;
                    }
                }
                plugin.getCheckTaskManager().put(player.getUniqueId(), checkParseBo);
            });
        });
    }
}
